/**
 * 描述 当前函数仅限在浏览器环境运行
 * 时间：2022-04-11
 * 作者：自夏
 */

import { imageType, NetworkType, SaveStorage } from '../entity/uni_Type';
import { InputFileOpentin, NewPictures } from '../Interface/util_Interface';
import { isType } from '../util/UtilityBox'
// import UtilString from './util/UtilString'

declare const window: any;

/**
* 计算图片的大小
* @param {} limit number
*/
export const conver = (limit: number): string => {
  let size = "";
  if (limit < 0.1 * 1024) {
    size = `${limit.toFixed(2)}B`;
  } else if (limit < 0.1 * 1024 * 1024) {
    size = `${(limit / 1024).toFixed(2)}KB`;
  } else if (limit < 0.1 * 1024 * 1024 * 1024) {
    size = `${(limit / (1024 * 1024)).toFixed(2)}MB`;
  } else {
    size = `${(limit / (1024 * 1024 * 1024)).toFixed(2)}GB`;
  }
  const sizestr = `${size}`;
  const len = sizestr.indexOf(".");
  const dec = sizestr.substr(len + 1, 2);
  if (dec === "00") {
    return sizestr.substring(0, len) + sizestr.substr(len + 3, 2);
  }
  return sizestr;
}

/**
* 获取Cookie值 传入Cookie名称
* @param name Cookie名称
* @returns {string|boolean} 对应的name值
*/
export const getCookie = (name: string = ''): string | boolean => {
  if (!name) throw Error('name参数必传!');
  const strcookie = document.cookie; //获取cookie字符串
  const arrcookie = strcookie.split("; "); //分割
  //遍历匹配
  for (let i = 0; i < arrcookie.length; i++) {
    let arr = arrcookie[i].split("=");
    if (arr[0] === name) {
      return arr[1];
    }
  }
  return "";
}


/**
 * 获取当前浏览器运行环境 是微信，支付宝，安卓，IOS,PC，移动，H5
 */
class runtimeEnvironment {
  public userAgent: string
  static userAgent: string;
  constructor() {
    this.userAgent = window?.navigator?.userAgent?.toLowerCase() as string
    runtimeEnvironment.userAgent = window?.navigator?.userAgent
  }

  /**
 * 判断是否是pc
 * @returns {boolean} false移动端页面 true为PC端
 */
  private getIplatfor(): boolean {
    return /ipad|iphone|midp|rv:1.2.3.4|ucweb|android|windows ce|windows mobile/.test(window?.navigator?.userAgent?.toLowerCase()) ? false : true;
  }


  /**
* 获取当前设备类型
* 不传入阐述就返回 PC端 PCend || 移动端 mobile
* 传入参数为移动端设备类型
 *
 * @param {传入'type'返回当前具体的设备类型,不传就 返回 PC端 PCend || 移动端 mobile'} type
 * @returns
 */
  getDeviceType = (type = null) => {
    let userAgentInfo = navigator.userAgent,
      flag, terminal = ['Android', 'iPhone', 'SymbianOS', 'Windows Phone', 'iPad', 'iPod'];
    if (type) {
      for (let i in terminal) {
        if (userAgentInfo.includes(terminal[i])) {
          return terminal[i];
        }
      }
      return 'PCend';
    } else {
      for (let v = 0; v < terminal.length; v++) {
        if (userAgentInfo.indexOf(terminal[v]) > 0) {
          flag = 'mobile';
          break;
        }
      }
      return flag === 'mobile' ? 'mobile' : 'PCend';
    }
  }

  // private  iosSystem(){
  //   return !!this.userAgent.match(/\(i[^;]+;( U;)? CPU.+Mac OS X/)
  // }

  /**
 * 是否在微信客户端
 * @returns boolean
 */
  protected isWX = /MicroMessenger/.test(runtimeEnvironment.userAgent)

  /**
   * 支付宝客服端
   * @returns boolean
   */
  protected isAliPay = /AlipayClient/.test(runtimeEnvironment.userAgent)

  /**
   * 安卓系统
   * @returns {boolean}
   */
  protected isAndroidSystem = /Android/.test(runtimeEnvironment.userAgent) || /Adr/.test(runtimeEnvironment.userAgent)

  /**
 * ios系统
 * @returns {boolean}
 */
  protected iosSystem = !!window?.navigator?.userAgent.match(/\(i[^;]+;( U;)? CPU.+Mac OS X/)

  /**
   * ios系统
   * @returns {boolean}
   */
  protected isPc = this.getIplatfor()

  /**
   * 是否是移动端
   * @returns {boolean}
   */
  protected isMobile = this.getIplatfor()


}

// /**
//  * 是否在微信客户端
//  * @returns boolean
//  */
// export const isWXh5 = /MicroMessenger/.test(window?.navigator?.userAgent)

// /**
//  * 支付宝客服端
//  * @returns boolean
//  */
// export const isAliPay = /AlipayClient/.test(window?.navigator?.userAgent)


// /**
//  * 安卓系统
//  * @returns {boolean}
//  */
// export const androidSystem = (): boolean => {
//   let ua = navigator.userAgent;
//   return ua.indexOf('Android') > -1 || ua.indexOf('Adr') > -1
// }

// /**
//  * ios系统
//  * @returns {boolean}
//  */
// export const iosSystem = (): boolean => {
//   let ua = navigator.userAgent;
//   return !!ua.match(/\(i[^;]+;( U;)? CPU.+Mac OS X/)
// }

// /**
//  * 判断是否是pc
//  * @returns {boolean} false移动端页面 true为PC端
//  */
// export const isPc = (): boolean => {
//   let ua = navigator.userAgent.toLowerCase();
//   return /ipad|iphone|midp|rv:1.2.3.4|ucweb|android|windows ce|windows mobile/.test(ua) ? false : true;
// }


/**
 * 反调试
 * @param {*} ban
 */
export function debugging(ban: any) {
  let {
    Noright = true, NoKeyDown = true, debug = true
  } = ban || {};
  if (Noright) { //禁止鼠标右键
    document.onkeydown = document.onkeyup = document.onkeypress = function (event) {
      event.returnValue = false;
      return false;
    }
  }
  if (NoKeyDown) { //禁部分按键和组合键
    //document.onkeydown = document.onkeyup = document.onkeypress
    document.onkeydown = function (event) {
      // 放开 复制粘贴和全选，以及禁用f1-f12
      const releaseKey: Array<string> = ['c', 'v', 'a'], FkeyCode: Array<number> = [112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123];
      const { ctrlKey, shiftKey, altKey, key, keyCode } = event
      // 禁用 F1-F12
      if (FkeyCode.includes(keyCode)) return false;
      // 除组 预定的组合键，其他都禁用
      if (ctrlKey && !releaseKey.includes(key)) {
        ctrlKey || shiftKey || altKey && (event.returnValue = false);
        return false;
      }
    }
  }
  if (debug) { //反调试代码
    (() => {
      const handler = setInterval(() => {
        const before = new Date();
        debugger;
        const after = new Date();
        // 如果不打开调试模式的话,肯定不会大于100
        const cost = after.getTime() - before.getTime();
        if (cost > 100) {
          clearInterval(handler)
        }
      }, 1000)
    })()
  }
}


/**
 * 获取当前网络状态
 * @param {回调函数} cb
 * @returns
 */
export const getNetwork = (cb: (cb: any) => void) => {
  // @ts-ignore
  const linkNet: NetworkType = navigator.connection, effectivetype = linkNet.effectiveType;

  const getNet = () => {
    const { downlink, effectiveType, rtt }: NetworkType = linkNet,

      is = (Boolean(downlink) || Boolean(rtt)), isAvailable = is ? (is && navigator.onLine) : false;

    return {
      Details: { downlink, effectiveType, rtt },
      BeforeType: effectivetype, // 切换前的
      CurrentType: linkNet.effectiveType, // 切换后的
      Available: isAvailable // 当前网络是否可用
    }
  }
  // 监听网络切换
  // @ts-ignore
  cb instanceof Function && linkNet.addEventListener('change', () => {
    cb(getNet())
  });

  return getNet()
}





export const screnn = () => {
  return new (class screnn {
    public d
    public el
    constructor(data = { el: 'body', }) {
      const { el } = data;
      this.d = document;
      this.el = document.querySelector(el || 'body')
    }

    /**
     *
     * @param getInto 进入全屏时的回调函数
     * @param cb 自定义回调函数
     */
    LockMouse(getInto: () => void, cb: any) {

      let d: any = document;

      //进入全屏时触发
      const fullscreenChange = () => {

        if (d.webkitFullscreenElement === this.el || d.mozFullscreenElement === this.el || d.mozFullScreenElement === this.el) { // 较旧的 API 大写 'S'.
          // 元素进入全屏模式了，现在我们可以请求指针锁定。
          // console.log(this.el);
          if (this.el) {
            // @ts-ignore
            this.el.requestPointerLock = this.el.requestPointerLock || this.el.mozRequestPointerLock || this.el.webkitRequestPointerLock;
            this.el.requestPointerLock();
            getInto()
            // console.log('全屏了')
          } else {
            throw Error('进入全屏失败')
          }
        }
      }

      this.d.addEventListener('fullscreenchange', fullscreenChange, false);
      this.d.addEventListener('mozfullscreenchange', fullscreenChange, false);
      this.d.addEventListener('webkitfullscreenchange', fullscreenChange, false);

      const pointerLockChange = () => {
        // console.error(d.webkitPointerLockElement);
        if (d.mozPointerLockElement === this.el || d.webkitPointerLockElement === this.el) {
          // console.log("指针锁定成功了。");
        } else {
          // console.log("指针锁定已丢失。");
        }
      }

      this.d.addEventListener('pointerlockchange', pointerLockChange, false);
      this.d.addEventListener('mozpointerlockchange', pointerLockChange, false);
      this.d.addEventListener('webkitpointerlockchange', pointerLockChange, false);

      function pointerLockError() {
        // console.log("锁定指针时出错。");
      }
      this.d.addEventListener('pointerlockerror', pointerLockError, false);
      this.d.addEventListener('mozpointerlockerror', pointerLockError, false);
      this.d.addEventListener('webkitpointerlockerror', pointerLockError, false);
    }

    /**
     * 退出全屏
     * @param cb 退出时的回调函数
     */
    close(cb: any) {
      let d: any = document;
      d.exitFullScreen ? d.exitFullScreen() : d.mozCancelFullScreen ? d.mozCancelFullScreen() : d.webkitExitFullscreen ? d.webkitExitFullscreen() : d.msExitFullscreen ? d.msExitFullscreen() : '';
      d.exitFullscreen
    }

    open() {
      const $el: any = document.documentElement;
      const rfs = $el.requestFullScreen || $el.webkitRequestFullScreen || $el.mozRequestFullScreen || $el.msRequestFullscreen;
      if (typeof rfs != 'undefined' && rfs) {
        rfs.call($el);
      }
      return;
    }
  }
  )()
}




type Params = {
  title: string, body: string, icon?: string, image?: string
}
interface callback {
  show?: (e: Event) => void
  click?: (e: Event) => void
  close?: (e: Event) => void
  error?: (e: Event) => void
}

export class alerts {
  private datNotice
  private cb
  private notify!: Notification;
  /**
   * 浏览器通知
   * @param _datNotice 通知得内容 { title: string, body: string, icon?: string, image?: string}
   * @param _cb 回调对象 callback {  show?: (e: Event) => void   click?: (e: Event) => void  close?: (e: Event) => void  error?: (e: Event) => void}
   */
  constructor(_datNotice: Params, _cb: callback) {
    this.datNotice = _datNotice;
    this.cb = _cb;

    const { title, body, icon, image } = this.datNotice;
    if (!('Notification' in window)) { console.error('当前浏览器不支持通知'); }

    //denied (用户拒绝了通知的显示), granted (用户允许了通知的显示), 或 default (因为不知道用户的选择，所以浏览器的行为与 denied 时相同)
    if (['denied', 'default'].includes(Notification.permission)) {
      throw Error('请同意浏览器通知,正式环境使用HTTPS域名，否则无法弹出权限，本地开发请使用localhost 打开地址');
    }
    Notification.requestPermission().then((status => {
      // 同意了通知
      if (status === 'granted') {
        this.notify = new Notification(`${title || '通知'}`, {
          body, // 通知中额外显示的字符串
          data: 3000,
          dir: "auto", // 文字的方向；它的值可以是 auto（自动）, ltr（从左到右）, or rtl（从右到左）
          icon, //一个图片的URL，将被用于显示通知的图标
          image,
          lang: "",  //  指定通知中所使用的语言
        })

        this.notify.addEventListener('show', this.onshow, false)
        this.notify.addEventListener('click', this.onclick, false)
        this.notify.addEventListener('close', this.onclose, false)
        this.notify.addEventListener('error', this.onerror, false)
      }
    }))
  }
  private onshow(e: any) {
    // console.log('桌面消息显示时', e)
    this.cb?.show instanceof Function && this.cb.show(e)
  }
  private onclick(e: any) {
    // console.log('点击时桌面消息时触发', e)
    this.cb?.click instanceof Function && this.cb.click(e)
  }
  private onclose(e: any) {
    // console.log('点击时桌面关闭触发', e)
    this.cb?.close instanceof Function && this.cb.close(e)
  }
  private onerror(e: any) {
    // console.log('错误时触发', e)
    this.cb?.error instanceof Function && this.cb.error(e)
  }
}


export class applicationStorage {
  /**
   *
   * @param {} key Boolean key是否加密
   *  @param {} data Boolean data是否加密
   *  @param {存储的数据类 localStorage 还是 sessionStorage 默认 sessionStorage } type
   * @param {} overtime Boolean 超时删除
   */
  constructor(private isEncryptionKey?: Boolean, private isEncryptionData?: Boolean, private type?: 'local' | 'session', private overtime?: boolean) { }
  /**
   * 加密数据
   * @param {any} data 转为base64数据
   */
  encrypt(data: string | Object): string
  encrypt(data: string): string {
    if (isType(data) === 'Object') {
      let set = encodeURIComponent(this.objectSwitchString(data) as string), result = btoa(set);
      return result
    } else {

      let set = encodeURIComponent(data), result = btoa(set);
      return result;
    }
  }
  /**
   * 解码数据
   * @param {any} data 数据
   */
  MyLocker(data: string) {
    try {
      let jieMi = atob(data), jieM = decodeURIComponent(jieMi);
      return jieM;
    } catch (e) {
      throw Error('解码出错')
    }
  }
  /**
   *  根据参数区分存储对象
   * @param Session
   * @returns {Storage} 返回 Session 存储对象
   */
  private isSession(Session: string | undefined) {
    return Session === 'local' ? localStorage : sessionStorage;
  }
  /**
   * 判断该当前的key 是否存在
   * @param key
   * @constructor
   */
  private ISKET(key: string) {
    if (!key) {
      throw Error('请传入Session的KEY!!!')
    }
  }
  /**
   * Object 类型转为 string 非Object 类型则返回源数据
   * @param setObj
   * @returns
   */
  private objectSwitchString(setObj: Object | string): string | any {
    if (isType(setObj) !== 'Object') return setObj;
    return JSON.stringify(setObj);
  }
  /**
   * Session存储方法
   * @param key 存储的key值
   * @param setObj 存储的数据
   * @param overdueTime 过期时间 1000=1秒
   */
  setSession(key: string, setObj: any, overdueTime?: number) {
    this.ISKET(key);
    let setdata: SaveStorage = {
      type: isType(setObj) as string,
      data: this.objectSwitchString(setObj)
    }
    overdueTime && (setdata.time = new Date().getTime() + overdueTime)
    setObj = this.objectSwitchString(setdata)
    this.isSession(this.type).setItem(this.isEncryptionKey ? this.encrypt(key) : key, this.isEncryptionData ? this.encrypt(setObj) : setObj);
  }
  /**
   * 获取存储的值
   * @param key 存储的key
   * @returns {any} 返回对应的key 的数据
   */
  getSession(key: string) {
    this.ISKET(key);
    let data = this.isSession(this.type).getItem(this.isEncryptionKey ? this.encrypt(key) : key) as string;
    const getTime: number = new Date().getTime()
    if (data && this.isEncryptionData) {
      // try {
      const { data: getdata, type, time } = JSON.parse(this.isEncryptionData ? this.MyLocker(data) : data)
      if (getTime < time && time) {
        return type === 'Object' ? JSON.parse(getdata) : getdata
      } else if (getTime > time && time) { // 时间过期
        return this.overtime ? this.removeItem(key) : null
      } else {
        return type === 'Object' ? JSON.parse(getdata) : getdata
      }
      // } catch (e) {
      //   console.log(data, 222);
      //   return this.isEncryptionData ? this.MyLocker(data) : data
      // }
    } else {
      if (!data) return undefined;
      // try {
      const { data: getdata, type, time } = JSON.parse(data)
      // 时间没有过期
      if (getTime < time && time) {
        return type === 'Object' ? JSON.parse(getdata) : getdata
      } else if (getTime > time && time) { // 时间过期
        return this.overtime ? this.removeItem(key) : null
      } else {
        return type === 'Object' ? JSON.parse(getdata) : getdata
      }
      // } catch (error) {
      //   console.log(data, 444);
      //   return data
      // }
    }
  }

  /**
   * 删除 指定单个key
   * @param key
   * @param Session
   */
  removeItem(key: string) {
    this.ISKET(key);
    this.isSession(this.type).removeItem(this.isEncryptionKey ? this.encrypt(key) : key);
  }

  /**
   * 删除所有可以
   * @param Session
   */
  removeAll() {
    this.isSession(this.type).clear();
  }
  watchStorage() {

    // 创建一个StorageEvent事件
    // var newStorageEvent = document.createEvent('StorageEvent');
    // newStorageEvent.initStorageEvent('setItem', false, false, , null, val, null, null);

    // console.log(newStorageEvent.initStorageEvent);
    // window.onstorage = (e) => {
    //   console.log(e, 11111111);
    // }
    setTimeout(() => {
      window.addEventListener('storage', (e) => {
        console.log(e, 11111111);
      })
    }, 1000);

  }
}

/**
 * 浏览器事件循环 Promise 错误没有被处理
 * @param hadeleRejection
 */
export const browserEventTopPromiseError = (hadeleRejection: Function) => {
  let poccibyunhandledRejection = new Map();

  window.onunhandledrejection = (event: any) => {
    poccibyunhandledRejection.set(event.promise, event.reason);
  };

  window.onrejectionhandled = (event: any) => {
    poccibyunhandledRejection.delete(event.promise);
  };

  setInterval(() => {
    poccibyunhandledRejection.forEach((reason, promise) => {
      console.log(reason.message ? reason.message : reason);
      hadeleRejection(promise, reason)
    });

    poccibyunhandledRejection.clear();
  }, 6000);
}


class createElement {
  /**
 * 创建元素
 * @param NodeName 节点(dom)类型
 * @returns HTMLElement
 */
  createElement(NodeName: string = 'a'): HTMLElement | HTMLCanvasElement | HTMLAnchorElement | HTMLCanvasElement {
    return document.createElement(NodeName);
  }
}

/**
 * 文件下载
 */
export class download extends createElement {
  public node: HTMLElement
  constructor() {
    super()
    this.node = this.createElement()
  }


  /**
   * 链接内容下载
   * @param link 链接
   */
  aLink(link: string, fileName?: string) {
    const element = this.node as HTMLAnchorElement
    element.href = link
    element.download = fileName || '保存文件'
    element.click()
  }

  /**
   * 使用http 请求下载内容
   * @param url 内容地址
   */
  dwHttpRequest(url: string) {
    // const element = this.node as HTMLAnchorElement
    const xhr: XMLHttpRequest = new XMLHttpRequest(), a = this;
    xhr.open('get', url);
    // 把请求类型设置为 blob
    xhr.responseType = 'blob';
    xhr.send();
    xhr.onload = function (sues) {
      const data = xhr.response;
      // 把请求回来的blob数据 转为 blob 本地路径 进行下载 这个样不会出现跨域问题
      const imgurl = URL.createObjectURL(data)
      a.aLink(imgurl)
      // 创建一个 单击事件
      // let event = new MouseEvent('click')
      // element.setAttribute('download', '');
      // element.setAttribute('href', imgurl);
      // // 执行单击方法  这里调用此方法就可触发
      // element.dispatchEvent(event);
    }
  }

  /**
   * 下载图片
   * @param imgsrc 地盘地址
   * @param name 图片下载的名称
   */
  downloadIamge(imgsrc: string, name = '图片名称') {
    const canvas: HTMLCanvasElement = this.createElement('canvas') as HTMLCanvasElement, a = this;
    // const a = this.node as HTMLAnchorElement
    //下载图片地址和图片名
    let image = new Image();
    // 解决跨域 Canvas 污染问题
    image.setAttribute('crossOrigin', 'anonymous');

    image.onload = function () {
      canvas.width = image.width;
      canvas.height = image.height;
      let context: CanvasRenderingContext2D = canvas.getContext('2d') as CanvasRenderingContext2D
      context.drawImage(image, 0, 0, image.width, image.height);
      let url = canvas.toDataURL('image/png'); //得到图片的base64编码数据
      a.aLink(url, name)
      // let a = document.createElement('a'); // 生成一个a元素
      // let event = new MouseEvent('click'); // 创建一个单击事件
      // a.download = name; // 设置图片名称
      // a.href = url; // 将生成的URL设置为a.href属性
      // a.dispatchEvent(event); // 触发a的单击事件
    };
    image.src = imgsrc;
  }

  /**
   *
   * @param content 下载内容
   * @param type 保存的文件类型 类型参考地址
     * https://www.w3school.com.cn/media/media_mimeref.asp
   * @param fileName 文件名称
   * @param suffix 文件后缀
   */
  dwContent(content: string, type: string, fileName: string, suffix: string) {
    let blob = new Blob([content], { type: type });
    let objectURL = URL.createObjectURL(blob); // 创建URL   blob:https://www.xxx.com/285f734a-0f3a-4f01-b1cc-b95b29d7fd05 此链接可以下载
    this.aLink(objectURL, fileName + suffix)
    URL.revokeObjectURL(objectURL); // 释放内存
  }
}




class FileSelection extends createElement {
  blobUrls: string[]
  public createfile!: HTMLInputElement;
  // HTMLInputElement

  constructor() {
    super()
    this.blobUrls = []
  }
  /**
   * 创建文件选择器
   */
  openFiles(Option: InputFileOpentin) {
    this.createfile = document.createElement('input')

    this.createfile.type = 'file'

    // const fileOpend:InputFileOpentin = {
    //   multipl:Boolean,
    //   accept:MimeType,
    //   capture:"camera"|"user"|"camcorder"|"microphone"|"environment",
    //   directory:Boolean
    // }

    console.log(Option, 'Option')
    for (const key in Option) {
      this.createfile[key] = Option[key]
    }

    // Option.webkitdirectory
    // this.createfile.multiple = true // 是否支持多选
    // this.createfile.accept  // 接受的文件类型  audio/*， 表示 “任何音频文件”。video/*，表示 “任何视频文件”。 image/*，表示 “任何图片文件”。
    // this.createfile.accept = "image/*"
    // this.createfile.capture = "environment" //  camera 打开摄像头 user 打开前置摄像头  camcorder 打开录像 microphone 打开录音机  environment 打开后置摄像头
    // this.createfile.webkitdirectory = true // 选择一个目录（或多个目录，如果 multiple 也出现的话）
    // let event = new MouseEvent('click')
    // this.createfile.dispatchEvent(event);
    this.createfile.onchange = async (even: Event) => {
      // console.log(even,'even');
      // console.log(even.path, even.path[0].files);
      // @ts-ignore
      let fl = even?.target || even?.path[0], files: Array<File>
      files = fl.files
      // await this.FileReader(this.files[0])
      // this.FileShardRead(this.files[0])
      console.log(files);

      this.getVideofirstFrame(files[0])
      // this.photoCompression(this.FilePreview(this.files[0]))
    }
    this.createfile.click()
    // document.removeChild(this.createfile);
  }

  FileReader(files: File) {
    // this.FilePreview(files)
    return new Promise((resolve, reject) => {
      const reader = new FileReader() // 这是核心,读取操作就是由它完成.
      console.log(reader, files);
      // 读取错误时
      reader.addEventListener('error', (err) => {
        // console.error(123111, err.target.error)
      })
      // 读取完成
      reader.onload = (result) => {
        // 当读取完成后回调这个函数,然后此时文件的内容存储到了result中,直接操作即可
        // this.content += result?.target?.result
        console.log('读取完成', result.target);
      }
      // 读取操作发生错误
      reader.onerror = (err) => {
        console.log('读取操作发生错误', err);
      }
      //读取操作被中断
      reader.onabort = () => {
        console.log('读取操作被中断');
      }
      //读取操作开始时触发
      reader.onloadstart = () => {
        console.log('读取操作开始时触发');
      }
      //读取操作结束时（要么成功，要么失败）触发
      reader.onloadend = () => {
        console.log('读取操作结束时');
      }
      //该事件在读取Blob时触发。
      reader.onprogress = (e) => {
        console.log('该事件在读取', Math.ceil((e.loaded / e.total) * 100));
      }

      //EMPTY	0	还没有加载任何数据。
      //LOADING	1	数据正在被加载。
      //DONE	2	已完成全部的读取请求。
      reader.addEventListener('readyState', (err) => {
        console.error("readyState", err)
      })

      // console.log('readyState',reader.readyState);
      //开始读取指定的Blob中的内容。一旦完成，result属性中将包含一个data: URL 格式的 Base64 字符串以表示所读取文件的内容。
      // reader.readAsDataURL(files)
      //中止读取操作
      // reader.abort()
      //开始读取指定的Blob中的内容。一旦完成，result属性中将包含所读取文件的原始二进制数据
      // reader.readAsBinaryString(files[0])
      //开始读取指定的Blob中的内容。一旦完成，result属性中将包含一个字符串以表示所读取的文件内容。
      // reader.readAsText(files[0], 'utf-8') // 读取文件的内容,也可以读取文件的URL

      // 开始读取指定的 Blob中的内容，一旦完成，result 属性中保存的将是被读取文件的 ArrayBuffer 数据对象。
      reader.readAsArrayBuffer(files)
    })
  }
  getSpecifyTxt(str: string, findStr = ".") {
    // if (!str) return;
    const partition = str?.lastIndexOf(findStr);
    return {
      name: str.substring(0, partition),
      suffix: str.substring(partition, str.length)
    };
  }

  /**
   * 将blob转换为file
   * @param dataurl base64字符串
   * @param filename 文件名称
   * @returns
   */
  base64toFile(dataurl: string, filename: string) {
    var arr: Array<any> = dataurl.split(','),
      mime = arr[0].match(/:(.*?);/)[1],
      bstr = atob(arr[1]),
      n = bstr.length,
      u8arr = new Uint8Array(n);
    while (n--) {
      u8arr[n] = bstr.charCodeAt(n);
    }
    return new File([u8arr], filename, { type: mime });
  }


  /**
   * 将base64转换为blob
   * @param dataurl  base64 字符串
   * @returns
   */
  dataURLtoBlob(dataurl) {
    var arr = dataurl.split(','),
      mime = arr[0].match(/:(.*?);/)[1],
      bstr = atob(arr[1]),
      n = bstr.length,
      u8arr = new Uint8Array(n);
    while (n--) {
      u8arr[n] = bstr.charCodeAt(n);
    }
    return new Blob([u8arr], { type: mime });
  }
  /**
   * 将blob转换为file
   * @param theBlob Blob
   * @param fileName 文件名称
   * @returns
   */
  blobToFile(theBlob, fileName) {
    theBlob.lastModifiedDate = new Date();
    theBlob.name = fileName;
    return theBlob;
  }

  FileShardRead(files: File) {
    const {
      name,
      suffix
    } = this.getSpecifyTxt(files.name)
    const chunkSize = (1024 * 1024) * 10; // 文件分片大小
    const fromdata = new FormData()
    const Read = (index: number) => {
      const start = index * chunkSize; //切片的大小
      if (start > files.size) {
        return fromdata
      }
      // console.log(start, start + chunkSize);
      let blob = files.slice(start, start + chunkSize),
        blobName = `${name},${index},${suffix}`,
        blobFile = new File([blob], blobName, {
          type: files.type,
        });
      fromdata.append(String(index), blobFile, blobName)
      Read(++index)
    }
    Read(0)
  }

  /**
   * 文件预览
   * @param {Object} files 文件
   */
  FilePreview(files: File | Blob | Array<File>) {
    if ('length' in files) {
      return [...files].map(file => {
        return {
          blobUrl: this.createPreview(file),
          file
        }
      })
    } else {
      return this.createPreview(files)
    }
  }

  /**
   * 创建预览
   * @param {Object} files
   */
  createPreview(files: Blob | File) {
    let blobs = window.URL.createObjectURL(files)
    this.blobUrls.push(blobs)
    return blobs
  }

  /**
   * 释放预览 创建预览将会别销毁
   * @param {Object} ObjectURL
   */
  releasePreview() {
    this.blobUrls.forEach(f => window.URL.revokeObjectURL(f))
  }

  /**
   * 图片压缩
   *  @param {String} src 压缩地址 src | blob:http
   *  @param {Number} w 压缩宽度
   *  @param {Number} h 压缩高度
   *  @param {Number} type DOMString 类型，指定图片格式，默认格式为 image/png。
   * @param {String} quality 值在 0 与 1 之间，当请求图片格式为 image/jpeg 或者 image/webp 时用来指定图片展示质
   */
  photoCompression(src: string, w = 200, h = 200, type: imageType = 'image/png', quality = 0.95) {
    new Promise<NewPictures>((resolve, reject) => {
      try {
        let img = new Image();
        img.src = src
        // 设置图片源跨越
        // img.crossOrigin=""
        // img.crossOrign="*"
        img.setAttribute('crossOrigin', 'anonymous');
        img.onerror = (err) => {
          reject(err)
        }
        img.onload = (lodImg) => {
          //图片的原始尺寸
          let originWidth = img.width,
            originHeight = img.height;
          //最大尺度的尺寸限制默认在 200*200
          let maxWidth = w, maxHeight = h;
          //目标尺寸
          let targetWidth = originWidth, targetHeight = originHeight;
          if (originWidth > maxWidth || originHeight > maxHeight) { //如果原始尺寸大于了设定的最大尺寸
            if (originWidth / originHeight > maxWidth / maxHeight) { //图片原本的宽高比例大于了设定的宽高比例
              //大于规定的比例 证明 原始宽度大于高度 -》所以按照高度除以宽度的比例去缩放高度
              targetWidth = maxWidth;
              targetHeight = Math.round(maxWidth * (originHeight / originWidth));
            } else {
              //小于则表明 原始高度大于原始宽度 -》所以按照宽度除以高度的比例去缩放宽度
              targetHeight = maxHeight;
              targetWidth = Math.round(maxHeight * (originWidth / originHeight));
            }
          }
          let canvas = this.createElement('canvas') as HTMLCanvasElement
          let context = canvas.getContext('2d') as CanvasRenderingContext2D
          // canvas对图片进行缩放
          canvas.width = targetWidth;
          canvas.height = targetHeight;
          // 清除画布
          context.clearRect(0, 0, targetWidth, targetHeight);
          // 图片压缩
          context.drawImage(img, 0, 0, targetWidth, targetHeight);
          // 回调函数返回的 blob 这个 blob 可穿件预览
          canvas.toBlob((blob) => {
            let d: NewPictures = {
              PreviewUrl: window.URL.createObjectURL(blob),
              data: canvas.toDataURL(type), // 返回得base64字符串
              file: this.blobToFile(blob, 'jpeg')
            }
            resolve(d)
          }, type, quality); //0.95

        }
      } catch (error) {
        reject(error)
      }
    })
  }

  /**
   * 获取视频中的某一个帧做封面
   * @param files
   * @param frame
   */
  getVideofirstFrame(files: File, frame: number = 5) {

    return new Promise<NewPictures>((resolve, reject) => {
      try {
        const {
          type,
          size,
          name
        } = files
        const Previewurl = this.FilePreview(files)
        let canvas = this.createElement('canvas') as HTMLCanvasElement;
        let context = canvas.getContext('2d') as CanvasRenderingContext2D
        let Video = this.createElement('video') as HTMLVideoElement;
        Video.src = Previewurl as string
        Video.setAttribute('type', type)
        Video.setAttribute('autoplay', 'autoplay') //  自动播放
        Video.setAttribute('preload', 'auto') // 播放之前预加载
        Video.setAttribute('muted', 'true') // 布尔属性 音频会初始化为静音
        Video.onloadedmetadata = () => {
          // 设置canvas宽高，不设置默认 300 * 150
          canvas.setAttribute('width', String(Video.videoWidth))
          canvas.setAttribute('height', String(Video.videoHeight))
          Video.currentTime = frame; // 设置播放时间 前0-2s可能为白屏或者黑屏
        };
        Video.onseeked = (e) => {
          context.drawImage(Video, 0, 0, Video.videoWidth, Video.videoHeight);
          const source: string = canvas.toDataURL('image/png', 0.92)
          let d: NewPictures = {
            PreviewUrl: window.URL.createObjectURL(this.base64toFile(source, name)),
            data: source,
            file: this.base64toFile(source, name)
          }
          resolve(d)
        }
      } catch (error) {
        reject(error)
      }
    })
  }
}




// window.FileSelection = new FileSelection()
